computed 的实现原理
computed 接收一个 getter 函数,返回一个响应式的 ref 对象。其值在依赖变化时自动重新计算。
function computed(getter) {
// 1. 创建响应式引用存储计算结果
const result = ref()
// 2. 追踪 getter 中的依赖,变化时重新计算
effect(() => {
result.value = getter()
})
// 3. 返回 ref 对象
return result
}
javascript
使用示例
const product = reactive({ price: 10, quantity: 3 })
const salePrice = computed(() => product.price * 0.8)
const total = computed(() => salePrice.value * product.quantity)
console.log(total.value) // 24
product.price = 20
console.log(total.value) // 48
product.quantity = 5
console.log(total.value) // 80
javascript
computed 的惰性求值特性
与 effect 立即执行不同,computed 具有惰性求值(Lazy Evaluation)特性:
- 只有在
.value被读取时才计算 - 计算结果会被缓存,依赖不变时直接返回缓存值
- 依赖变化时标记为 dirty,下次读取时重新计算
Vue 源码中 computed 的实际实现比上面的简化版复杂得多,包含了脏标记(dirty flag)、缓存机制和调度器集成。
Vue 3 Proxy 带来的额外收益
动态属性添加
const product = reactive({ price: 10 })
// Vue 2 中需要 Vue.set(),Vue 3 直接赋值即可
product.name = 'iPhone' // 自动触发响应式更新
effect(() => {
console.log(product.name) // 自动追踪 name 属性
})
product.name = 'iPad' // 控制台自动打印 'iPad'
javascript
对比 Vue 2
// Vue 2 的痛点
this.product.name = 'iPhone' // ❌ 非响应式
this.$set(this.product, 'name', 'iPhone') // ✅ 需要特殊 API
// Vue 3 的体验
const product = reactive({ price: 10 })
product.name = 'iPhone' // ✅ 直接赋值,自动响应式
javascript
源码验证方法
通过构建 Vue 源码并在 Node.js 中测试,验证自实现的 API 与源码行为一致。
构建步骤
# 克隆源码(建议使用课程对应的版本,如 3.5.13)
git clone https://github.com/vuejs/core.git
cd core
# 安装依赖(需要 Node 20+)
pnpm install
# 构建所有包
pnpm run build
bash
测试脚本
在 packages/vue/dist/ 目录下创建测试文件:
// test.js
const { reactive, ref, computed, effect } = require('./vue.cjs')
const product = reactive({ price: 10, quantity: 3 })
const salePrice = computed(() => product.price * 0.8)
const total = computed(() => salePrice.value * product.quantity)
console.log('Before:', total.value) // 24
product.price = 20
console.log('After price change:', total.value) // 48
product.quantity = 5
console.log('After quantity change:', total.value) // 80
javascript
运行 node test.js,如果输出与浏览器中自实现的 API 行为一致,则验证成功。
响应式 API 速查
| API | 用途 | 源码文件 |
|---|---|---|
reactive() | 创建深层响应式对象 | reactivity/src/reactive.ts |
ref() | 创建响应式引用(支持基本类型) | reactivity/src/ref.ts |
computed() | 创建计算属性 | reactivity/src/computed.ts |
effect() | 注册副作用函数 | reactivity/src/effect.ts |
track() | 追踪依赖 | reactivity/src/effect.ts |
trigger() | 触发更新 | reactivity/src/effect.ts |
源码阅读建议
- 按依赖顺序阅读:先读
effect.ts(track/trigger),再读reactive.ts,最后读ref.ts和computed.ts - 善用 AI 工具:将源码目录作为上下文,让 AI 辅助解释关键函数
- 对照大纲视图:VS Code 中打开文件后查看 Outline,快速定位核心函数
↑